/*
   Copyright (C) 2011 Roman Belov <romblv@gmail.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "lib/io.h"
#include "lib/base.h"
#include "lang/parser.h"
#include "lang/signal.h"
#include "sim/args.h"
#include "sim/edsim.h"
#include "util/list.h"
#include "util/link.h"

struct lib_io_print_cust {
	void			*def;		/* deffered list link node */
	int			ctl;		/* use ctl pin or do not */
	const char		*format;	/* format string */
};

int
lib_io_print(struct module *m)
{
	int				arg[2];
	struct lib_io_print_cust	*cust;
	struct spec			*s;

	if ((cust = m->cust) != NULL) {

		if (glob.def_call) {

			edsim_lib_share_in(m, arg, 2);

			if (!cust->ctl || arg[1]) {
				printf(cust->format, arg[0]);
				putc('\n', stdout);
			}
		}
	}
	else {
		cust = malloc(sizeof(struct lib_io_print_cust));
		cust->def = link_node_alloc(m);
		list_insert(&glob.def_list, cust->def);

		s = spec_find(m, "ctl");
		if (s && s->type == SPEC_INT) cust->ctl = s->val.i;
		else edsim_lib_share_spec_fail_report(m, s);

		s = spec_find(m, "format");
		if (s && s->type == SPEC_STRING) cust->format = s->val.s;
		else edsim_lib_share_spec_fail_report(m, s);

		m->cust = cust;
	}

	return 0;
}

int
lib_io_break(struct module *m)
{
	int				arg[1];
	struct lib_io_print_cust	*cust;	/* using print structure */
	struct spec			*s;

	if ((cust = m->cust) != NULL) {

		if (glob.def_call) {

			edsim_lib_share_in(m, arg, 1);

			if (arg[0]) {
				puts(cust->format);
				putc('\n', stdout);
				fflush(stdout);
				exit(EXIT_FAILURE);
			}
		}
	}
	else {
		cust = malloc(sizeof(struct lib_io_print_cust));
		cust->def = link_node_alloc(m);
		list_insert(&glob.def_list, cust->def);

		s = spec_find(m, "format");
		if (s && s->type == SPEC_STRING) cust->format = s->val.s;
		else edsim_lib_share_spec_fail_report(m, s);

		m->cust = cust;
	}

	return 0;
}

void *
lib_io_get_cacl(const char *lib)
{
	if (!strcmp(lib, "io_print"))
		return lib_io_print;
	else if (!strcmp(lib, "io_break"))
		return lib_io_break;
	else
		return NULL;
}

